#include "TCPRecvThread.h"
#include "messagePickUp.h"
#include "networkessential.h"
#include "messagetype.h"
#include "global.h"
#include "messageCommon.h"
#include "messageCommonEx.h"
#include "messageMemberList.h"
#include "asgkaCreateAgreementThread.h"
#include "asgkaDelAgreementThread.h"
#include "asgkaAddAgreementThread.h"
#include "asgka_network.h"
#include "asgka_space.h"
#include "asgka_wnd_message.h"

#include <iostream>
using namespace std;

TCPRecvThread::TCPRecvThread()
:m_single_member(NULL),
 m_group_center(NULL)
{}

TCPRecvThread::TCPRecvThread(singleMember *single_member, 
							 groupCenter *group_center,
							 memberCenter *member_center)
:m_single_member(single_member),
 m_group_center(group_center),
 m_member_center(member_center)
{}

void TCPRecvThread::init(singleMember *single_member, 
						 groupCenter *group_center,
						 memberCenter *member_center)
{
	m_single_member = single_member;
	m_group_center  = group_center;
	m_member_center = member_center;
}

UINT TCPRecvThread::threadWork()
{
	if (m_single_member == NULL && m_group_center == NULL)
		return -1;

	void (TCPRecvThread::*handle[20])(char *) = {
		&TCPRecvThread::handleDummy,					// 0x00
		&TCPRecvThread::handleMessageKeyPubH,			// 0x01
		&TCPRecvThread::handleMessageKeyPubO,			// 0x02
		&TCPRecvThread::handleMessageKeyPubR,			// 0x03
		&TCPRecvThread::handleMessageKeyPubA,			// 0x04
		&TCPRecvThread::handleMessageCiphertext,		// 0x05
		&TCPRecvThread::handleMessageGroupInvit,		// 0x06
		&TCPRecvThread::handleMessageMemberList,		// 0x07
		&TCPRecvThread::handleMessagLeaveGroup,			// 0x08
		&TCPRecvThread::handleMessageMemberAdd,			// 0x09
		&TCPRecvThread::handleMessageOffLine,			// 0x0a
		&TCPRecvThread::handleMessageJoinGroup,			// 0x0b
		&TCPRecvThread::handleMessageKickOut,			// 0x0c
		&TCPRecvThread::handleDummy,					// 0x0d
		&TCPRecvThread::handleDummy,					// 0x0e
		&TCPRecvThread::handleDummy,					// 0x0f
		&TCPRecvThread::handleDummy,					// 0x10
		&TCPRecvThread::handleDummy,					// 0x11
		&TCPRecvThread::handleDummy,					// 0x12
		&TCPRecvThread::handleDummy						// 0x13
	};

	SOCKET thissock = m_single_member->getSock();
	// Now we start receiving data
	while (true)
	{
		unsigned int messagetype;
		int message_len;

		messagetype = RecvFourBytesFromNet<unsigned int>(thissock);
		if (messagetype == 0)
			return -2;

		message_len = RecvFourBytesFromNet<int>(thissock);
		if (message_len == 0)
			return -2;

		cout << "TCP receive !" << endl;
		cout << "===========================================================" << endl;
		cout << "Message recevied!" << endl;
		cout << "Type of message: " << messagetype << endl;
		cout << "Length of message: " << message_len << endl;

		char *buf = new char[message_len + 1];
		memset(buf, 0, message_len + 1);
		if (!recvData(thissock, buf, message_len))
			return -2;

		if (messagetype > 0x13)
			continue;

		(this->*handle[messagetype])(buf);

		delete buf;
		cout << "===========================================================" << endl;
		cout << endl;
	}
}

void TCPRecvThread::handleMessageKeyPubH(char *str_message)
{
	cout << "Public key -- H" << endl;
	messagePickUp infopickup(str_message);
	asgka_element pubH;
	asgka_malloc(pubH);
	std::string groupname;
	infopickup.pickUpInfo(groupname, pubH);
	cout << "Group name: " << groupname << endl;
	cout << "Sender name: " << m_single_member->getMemberName() << endl;
	std::string strhrecv("Received H of the group named ");
	strhrecv.append(groupname);
	strhrecv.append("\r\nSender:");
	strhrecv.append(m_single_member->getMemberName());
	strhrecv.append("\r\nContent: ");
	strhrecv.append(pubH, LENGTH);
	strhrecv.append("\r\n");
	newLog(strhrecv);
	m_single_member->setpubH(groupname, pubH);
	asgka_free(pubH);
}

void TCPRecvThread::handleMessageKeyPubO(char *str_message)
{
	cout << "Public key -- O" << endl;
	messagePickUp infopickup(str_message);
	asgka_element pubO;
	asgka_malloc(pubO);
	std::string groupname;
	infopickup.pickUpInfo(groupname, pubO);
	cout << "Group name: " << groupname << endl;
	cout << "Sender name: " << m_single_member->getMemberName() << endl;
	std::string strorecv("Received O of the group named ");
	strorecv.append(groupname);
	strorecv.append("\r\nSender:");
	strorecv.append(m_single_member->getMemberName());
	strorecv.append("\r\nContent: ");
	strorecv.append(pubO, LENGTH);
	strorecv.append("\r\n");
	newLog(strorecv);
	m_single_member->setXigama(groupname, pubO);
	asgka_free(pubO);
}

void TCPRecvThread::handleMessageKeyPubR(char *str_message)
{
	cout << "Public key -- R" << endl;
	messagePickUp infopickup(str_message);
	asgka_element pubR;
	asgka_malloc(pubR);
	std::string groupname;
	infopickup.pickUpInfo(groupname, pubR);
	cout << "Group name: " << groupname << endl;
	cout << "Sender name: " << m_single_member->getMemberName() << endl;
	std::string strrrecv("Received R of the group named ");
	strrrecv.append(groupname);
	strrrecv.append("\r\nSender:");
	strrrecv.append(m_single_member->getMemberName());
	strrrecv.append("\r\nContent: ");
	strrrecv.append(pubR, LENGTH);
	strrrecv.append("\r\n");
	newLog(strrrecv);
	m_single_member->setpubR(groupname, pubR);
	asgka_free(pubR);
}

void TCPRecvThread::handleMessageKeyPubA(char *str_message)
{
	cout << "Public key -- A" << endl;
	messagePickUp infopickup(str_message);
	asgka_element pubA;
	asgka_malloc(pubA);
	std::string groupname;
	infopickup.pickUpInfo(groupname, pubA);
	cout << "Group name: " << groupname << endl;
	cout << "Sender name: " << m_single_member->getMemberName() << endl;
	std::string strarecv("Received A of the group named ");
	strarecv.append(groupname);
	strarecv.append("\r\nSender:");
	strarecv.append(m_single_member->getMemberName());
	strarecv.append("\r\nContent: ");
	strarecv.append(pubA, LENGTH);
	strarecv.append("\r\n");
	newLog(strarecv);
	m_single_member->setpubA(groupname, pubA);
	asgka_free(pubA);
}

void TCPRecvThread::handleMessageCiphertext(char *str_message)
{
	messagePickUp infopickup(str_message);
	std::string groupname;
	asgka_element ciphertext1;
	asgka_element ciphertext2;
	asgka_element ciphertext3;
	
	asgka_malloc(ciphertext1);
	asgka_malloc(ciphertext2);
	asgka_malloc(ciphertext3);

	infopickup.pickUpInfo(groupname, ciphertext1, ciphertext2, ciphertext3);

	std::string strcrecv("Received ciphertexts of the group named ");
	strcrecv.append(groupname);
	strcrecv.append("\r\nCiphertext1: ");
	strcrecv.append(ciphertext1, LENGTH);
	strcrecv.append("\r\nCiphertext2: ");
	strcrecv.append(ciphertext2, LENGTH);
	strcrecv.append("\r\nCiphertext3: ");
	strcrecv.append(ciphertext3, LENGTH);
	strcrecv.append("\r\n");
	newLog(strcrecv);

	singleGroup *target = m_group_center->getGroupByName(groupname);
	target->setCiphertext1(ciphertext1);
	target->setCiphertext2(ciphertext2);
	target->setCiphertext3(ciphertext3);

	asgka_free(ciphertext1);
	asgka_free(ciphertext2);
	asgka_free(ciphertext3);
}

void TCPRecvThread::handleMessageMemberList(char *str_message)
{
	cout << "Member list !" << endl;
	messagePickUp infopickup(str_message);
	std::string groupname;
	std::map<std::string, u_long> tempmap;

	infopickup.pickUpInfo(groupname, tempmap);

	cout << "Name of group: " << groupname << endl;

	// Now we create the singleMember objects and add them to the certain group
	std::map<std::string, u_long>::iterator it = tempmap.begin();
	while (it != tempmap.end())
	{
		cout << "Member: " << it->first << endl;

		EnterCriticalSection(&globalcs);
		bool ex = m_member_center->isMemberExisted(it->first);
		LeaveCriticalSection(&globalcs);

		singleMember *pMember = NULL;
		int retval;
		sockaddr_in addr;
		addr.sin_family = AF_INET;
		addr.sin_port = htons(TCPListenPort);
		addr.sin_addr.S_un.S_addr = it->second;

		SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
		if (!ex)
		{
			cout << "Connect to " << inet_ntoa(addr.sin_addr) << endl;
			retval = connect(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));

			cout << "TCP connected to " << it->first << endl;
			// Success
			if (retval == 0)
			{
				messageBase *message = new messageCommon(localname, NET_MESSAGE_SELF_INFO);
				sendMessageBySocket(message, sock);
				EnterCriticalSection(&globalcs);
				pMember = m_member_center->createMember(it->first, it->second, sock);
				LeaveCriticalSection(&globalcs);
			}
		}

		singleGroup *pGroup = m_group_center->getGroupByName(groupname);
		if (pMember != NULL)
		{
			pGroup->addAMember(pMember);

			// Changed
			TCPRecvThread *tempThread = new TCPRecvThread(pMember, m_group_center, m_member_center);
			tempThread->start();

			cout << "TCPRecv Thread start: " << it->first << endl;
		}
		else
		{
			cout << "Member existed !" << endl;
			singleMember *toaddMember = m_member_center->getMemberByName(it->first);
			pGroup->addAMember(toaddMember);
			closesocket(sock);
		}

		it++;
	}

	Sleep(AgreementWait);

	// Start agreement thread
	asgkaCreateAgreementThread *pthread = new asgkaCreateAgreementThread(m_group_center->getGroupByName(groupname));
	pthread->start();
}

void TCPRecvThread::handleMessageGroupInvit(char *str_message)
{
	cout << "Group invitation!" << endl;
	messagePickUp pickinfo(str_message);
	std::string inviter;
	std::string groupname;

	pickinfo.pickUpInfo(inviter, groupname);

	cout << "Inviter: " << inviter << endl;
	cout << "Name of group: " << groupname << endl; 

	singleMember *leader = m_member_center->getMemberByName(inviter);
	m_group_center->createGroup(groupname, leader); 
	
	cout << "Object singleGorup created!" << endl;

	notifyWnd(ASGKA_GRP_INV, inviter, groupname);
}

void TCPRecvThread::handleMessagLeaveGroup(char *str_message)
{
	cout << "Leave Group!" << endl;
	messagePickUp pickinfo(str_message);
	std::string sender;
	std::string groupname;

	pickinfo.pickUpInfo(sender, groupname);
	cout << sender << " want to leave group " << groupname << endl;

	m_group_center->DelMemberFromGroup(groupname, sender);
	notifyWnd(ASGKA_GRP_LEV, sender, groupname);
}

void TCPRecvThread::handleMessageOffLine(char *str_message)
{
	cout << "OFF LINE!" << endl;
	messagePickUp pickup(str_message);
	std::string sender;

	pickup.pickUpInfo(sender);
	cout << sender << " Off Line" << endl;

	m_group_center->DelMemberFromAllGroup(sender);
	while (!m_member_center->releaseMember(sender)) 
		Sleep(10);
	notifyWnd(ASGKA_OFF_LIE, sender);
}

void TCPRecvThread::handleMessageJoinGroup(char *str_message)
{
	cout << "Join Group !" << endl;
	messagePickUp pickup(str_message);
	std::string groupname;
	std::string sender;

	pickup.pickUpInfo(sender, groupname);
	notifyWnd(ASGKA_GRP_ASK, sender, groupname);
}

void TCPRecvThread::handleMessageMemberAdd(char *str_message)
{
	cout << "New Member!" << endl;
	messagePickUp pickup(str_message);
	std::string memberName;
	std::string groupname;
	pickup.pickUpInfo(memberName, groupname);

	cout << "membername: " << memberName << endl;
	cout << "groupname: " << groupname << endl;

	if (memberName.compare(localname) == 0)
		return;

	singleGroup *pGroup = m_group_center->getGroupByName(groupname);
	if (pGroup == NULL)
		return ;

	singleMember *pMember = m_member_center->getMemberByName(memberName);
	if (pMember == NULL)
		return;

	pGroup->addAMember(pMember);

	Sleep(AgreementWait);

	asgkaAddAgreementThread *pThread = new asgkaAddAgreementThread(pGroup, memberName);
	pThread->start();
	notifyWnd(ASGKA_GRP_ADD, memberName, groupname);
	cout << "Add agreement thread start! " << endl;
}

void TCPRecvThread::handleMessageKickOut(char *str_message)
{
	cout << "KICK OUT!!!" << endl;
	cout << "=================================================" << endl;
	std::string groupname; 
	std::string memberName;
	messagePickUp pickupInfo(str_message);
	pickupInfo.pickUpInfo(memberName, groupname);

	if (memberName.compare(localname) == 0)
	{
		m_group_center->releaseGroup(groupname);
	}
	else
	{
		m_group_center->DelMemberFromGroup(groupname, memberName);
	}
	cout << memberName << " is kicked out from " << groupname << endl; 
	cout << "================================================" << endl;

	notifyWnd(ASGKA_GRP_OUT, memberName, groupname);
}

void TCPRecvThread::handleDummy(char *str_message)
{
}